/**********************************************************************************
**
** Copyright (C) 2009 Jostein Bratlie
** Contact: jostein.bratlie@gmail.com | http://bratlie.info | http://episteme.hin.no
**
** This file is part of GMQtExt, a GMlib and Qt extension library
**
** GMQtExt is free software: you can redistribute it and/or modify
** it under the terms of the GNU Lesser General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** GMQtExt is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with GMQtExt.  If not, see <http://www.gnu.org/licenses/>.
**
**********************************************************************************/



// Qt
#include <QBoxLayout>

// QtSolutions
#include <qttreepropertybrowser.h>
#include <qtpropertymanager.h>
#include <qteditorfactory.h>
#include <qtvariantproperty.h>


// header
#include "propertybrowser.h"

namespace GMQtExt {

  PropertyBrowser::PropertyBrowser(QWidget* parent) : QWidget(parent) {

    // PropertyBrowser
    _browser = new QtTreePropertyBrowser( this );
    connect( _browser, SIGNAL(collapsed(QtBrowserItem*)), this, SLOT(_slotBrowserItemCollapsed(QtBrowserItem*)) );
    connect( _browser, SIGNAL(expanded(QtBrowserItem*)), this, SLOT(_slotBrowserItemExpanded(QtBrowserItem*)) );

    // Managers
    _group_manager = new QtGroupPropertyManager;
    _label_manager = new QtVariantPropertyManager;
    _vp_manager = new QtVariantPropertyManager;

    // Factories
    _browser->setFactoryForManager( _vp_manager, new QtVariantEditorFactory );

    // Widget layout
    QBoxLayout *layout = new QVBoxLayout;
    layout->setMargin(0);
    layout->addWidget(_browser);
    setLayout( layout );
  }

  PropertyBrowser::~PropertyBrowser() {

    delete _group_manager;
    delete _label_manager;
    delete _vp_manager;
  }

  void PropertyBrowser::_slotBrowserItemCollapsed( QtBrowserItem *item ) {

    _property_exp[ _property_id[item->property()] ] = false;
  }

  void PropertyBrowser::_slotBrowserItemExpanded( QtBrowserItem *item ) {

    _property_exp[ _property_id[item->property()] ] = true;
  }

  void PropertyBrowser::beginSetup() {

    _vp_manager->disconnect();
    _browser->clear();
    _property_id.clear();
    _property_id_status.clear();
  }

  void PropertyBrowser::beginUpdate() {}

  QtProperty* PropertyBrowser::createGroup( const QString& name, const QString& identifier, QtTreePropertyBrowser* browser, bool default_exp ) {

    QtProperty *group = _group_manager->addProperty( name );

    if(browser)
      browser->addProperty( group );

    registerProperty( group, identifier, default_exp );

    return group;
  }

  QtProperty* PropertyBrowser::createGroup( const QString& name, const QString& identifier, QtProperty* parent_group, bool default_exp ) {

    QtProperty *group = _group_manager->addProperty( name );

    if( parent_group )
      parent_group->addSubProperty(group);

    registerProperty( group, identifier, default_exp );

    return group;
  }

  QtVariantProperty* PropertyBrowser::createVariantLabel( int property_type, const QString& name, const QVariant& value, const QString& identifier, QtProperty* group, bool default_exp ) {

    QtVariantProperty *label;
    label = _label_manager->addProperty( property_type, name );
    _label_manager->setValue( label, value );

    if( group )
      group->addSubProperty(label);

    registerProperty( label, identifier, default_exp );

    return label;
  }

  QtVariantProperty* PropertyBrowser::createVariantProperty( int property_type, const QString& name, const QVariant& value, const QString& identifier, QtProperty* group, bool default_exp, QtVariantPropertyManager* manager ) {

    if( !manager )
      manager = _vp_manager;

    QtVariantProperty *property;
    property = manager->addProperty( property_type, name );
    property->setValue( value );

    if( group )
      group->addSubProperty( property );

    registerProperty( property, identifier, default_exp );

    return property;
  }

  void PropertyBrowser::endSetup() {

    // Connections
    connect( _vp_manager, SIGNAL(valueChanged(QtProperty*,QVariant)), this, SLOT(slotVariantPropertyChanged(QtProperty*,QVariant)) );
  }

  void PropertyBrowser::endUpdate() {

    QMap<QString,bool>::iterator end = _property_id_status.end();
    for( QMap<QString,bool>::iterator itr = _property_id_status.begin(); itr != end; ++itr ) {

      itr.value() = false;
    }
  }

  QtTreePropertyBrowser* PropertyBrowser::getBrowser() const {

    return _browser;
  }

  QtGroupPropertyManager* PropertyBrowser::getGroupManager() const {

    return _group_manager;
  }

  QtVariantPropertyManager* PropertyBrowser::getLabelManager() const {

    return _label_manager;
  }

  QtProperty* PropertyBrowser::getProperty( const QString& property_id ) const {

    return _property_id.key( property_id, 0x0 );
  }

  QtVariantProperty* PropertyBrowser::getVariantProperty(const QString &property_id) const {

    QtProperty* property = getProperty( property_id );
    return _vp_manager->variantProperty( property );
  }

  QString PropertyBrowser::getPropertyId( QtProperty* property ) const {

    if( !_property_id.contains(property) )
      return QString();

    return _property_id[property];
  }

  PROPERTYSTATUS PropertyBrowser::getPropertyStatus( const QString& property_id ) const {

    if( !_property_id_status.contains(property_id) )
      return PROPERTY_INVALID;

    if( _property_id_status.value(property_id) )
      return PROPERTY_CHANGED;

    return PROPERTY_UNCHANGED;
  }

  QVariant PropertyBrowser::getVariantPropertyValue( const QString& property_id, PROPERTYSTATUS& property_status ) const {

    property_status = getPropertyStatus( property_id );

    if( property_status == PROPERTY_INVALID )
      return QVariant();

    return getVariantProperty( property_id )->value();
  }

  QtVariantPropertyManager* PropertyBrowser::getVariantPropertyManager() const {

    return _vp_manager;
  }

  void PropertyBrowser::markPropertyAsChanged( QtProperty* property ) {

    QString property_id = getPropertyId( property );
    if( _property_id_status.contains(property_id) )
      _property_id_status[property_id] = true;
  }

  void PropertyBrowser::registerProperty( QtProperty* property, const QString& identifier, bool default_exp ) {

    _property_id_status[identifier] = false;
    _property_id[property] = identifier;
    if( !_property_exp.contains( _property_id[property] ) ) {

      QList<QtBrowserItem*> bis;
      bis += _browser->items( property );
      foreach( QtBrowserItem* bi, bis )
        if( bi->property() == property )
          _browser->setExpanded( bi, default_exp );
    }
    else {

      QList<QtBrowserItem*> bis;
      bis += _browser->items( property );
      foreach( QtBrowserItem* bi, bis )
        if( bi->property() == property )
          _browser->setExpanded( bi, _property_exp.value( _property_id[property] ) );
    }
  }

  void PropertyBrowser::setBackgroundColor( QtProperty* property, const QColor& color ) {

    QList<QtBrowserItem*> bis;
    bis += getBrowser()->items(property);

    foreach( QtBrowserItem* bi, bis )
      getBrowser()->setBackgroundColor( bi, color );
  }

  void PropertyBrowser::slotVariantPropertyChanged( QtProperty* property, const QVariant& /*value*/ ) {

    markPropertyAsChanged( property );
    emit signPropertyChanged();
  }

} // END namespace GMQtExt




